<?php

/**
 * 字符串辅助类
 */

namespace Services;

class Validations
{
    // 邮箱
    const REG_EMAIL = '/^[^\@]+@.*\.[a-z]{2,6}$/i';

    // 手机号码
//    const REG_MOBILE = '/^[1][3-8]+\\d{9}$/';
    const REG_MOBILE = '/^1[34578]{1}\d{9}$/';

    // 座机号码
    const REG_TELEPHONE = '/^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$/';

    // qq
    const REG_QQ = '/^[1-9]\d{4,10}$/';

    // 价格:2位小数
    const REG_PRICE = '/^[0-9]+(.[0-9]{1,2})?$/';

    // 密码
    const REG_PASSWORD = '/^[\\~!@#$%^&*()-_=+|{}\[\],.?\/:;\'\"\d\w]{6,20}$/';

    // 名称
    const REG_NAME = '/^[0-9a-zA-Zxa0-xff_]$/';

    // 经度
    const REG_LNG = '/^-?([1]?[1-7][1-9]|[1]?[1-8][0]|[1-9]?[0-9])\.{1}\d{1,6}$/';

    // 纬度
    const REG_LAT = '/^-?([1-8]?[1-9]|[1-9]0)\.{1}\d{1,6}$/';

    // 过滤服务
    protected $filters;

    // 错误信息存储
    private $error = array();

    public function __construct(Filters $filters)
    {
        $this->filters = $filters;
    }

    /**
     * 返回第一条error信息
     *
     * @return null
     */
    public function getError()
    {
        return $this->error ? $this->error[0] : null;
    }

    /**
     * 设置一条error信息
     *
     * @param $message
     */
    public function setError($message)
    {
        $this->error[] = $message;
    }

    /**
     * 返回所有error信息
     *
     * @return null
     */
    public function getErrors()
    {
        return $this->error;
    }

    /**
     * 正则验证
     *
     * @param $str
     * @param $name
     * @param bool $nullable
     * @param string $reg
     * @param int $min
     * @param int $max
     * @return bool
     */
    public function regexp($str, $name, $nullable = false, $reg ='', $min = 0, $max = 0)
    {
        if (!$nullable && $this->isEmpty($str)) {;
            $this->error[] = $name ? '请输入' . $name : '暂无参数';

            return false;
        }

        if ( $reg ) {
            if (!$this->isEmpty($str)) {
                if (!preg_match($reg, $str)) {
                    $this->error[] = $name ? $name . '不合法' : '非法参数';

                    return false;
                }
            }
        }

        if ( ($min > 0 || $max > 0) && (mb_strlen($str) < $min || mb_strlen($str) > $max) ) {
            $this->error[] = $name ? (($min == 0) ? $name . '长度不能超过' . $max . '位' : $name . '长度在' . $min . '-' . $max . '位') : '字符串长度不合法';

            return false;
        }

        return true;
    }

    /**
     * 判断是否为空
     *
     * @param $str
     * @return bool
     */
    public function isEmpty($str)
    {
        return empty($str) ? true : false;
    }

    /**
     * 判断字符中是否为空 其他\n \r \r\n可以算作空字符串
     *
     * @param $str
     * @return bool
     */
    public function isEmptyAll($str)
    {
        return empty($this->filters->trimBlank($str)) ? true : false;
    }

    /**
     * 判断是否是名称
     *
     * @param $str
     * @param $nullable
     * @param int $min
     * @param int $max
     * @return bool
     */
    public function isName($str, $nullable = false, $min = 2, $max = 15)
    {
        $reg = '/^[0-9a-zA-Zxa0-xff_]$/';

        return $this->regexp($reg, $str, $nullable, $min, $max);
    }

    /**
     * 验证是否邮箱
     *
     * @param $str
     * @param string $name
     * @param bool $nullable
     * @return bool
     */
    public function isEmail($str, $name = '邮箱', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_EMAIL, 0, 50);
    }

    /**
     * 验证是否手机号码
     *
     * @param $str
     * @param string $name
     * @return bool
     */
    public function isMobile($str, $name = '手机号', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_MOBILE);
    }

    /**
     * 判断座机
     *
     * @param $str
     * @param string $name
     * @param bool $nullable
     * @return bool
     */
    public function isTelephone($str, $name = '座机号码', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_TELEPHONE);
    }

    /**
     * 验证密码
     *
     * @param $str
     * @param string $name
     * @param bool $nullable
     * @param int $min
     * @param int $max
     * @return bool
     */
    public function isPassword($str, $name = '密码', $nullable = false, $min = 6, $max = 16)
    {
        return $this->regexp($str, $name, $nullable, self::REG_PASSWORD, $min, $max);
    }

    /**
     * 是否是含有2位小数的价格
     *
     * @param $str
     * @param string $name
     * @param bool $nullable
     * @param int $min
     * @param int $max
     * @return bool
     */
    public function isPrice($str, $name = '金额', $nullable = false, $min = 6, $max = 16)
    {
        return $this->regexp($str, $name, $nullable, self::REG_PRICE, $min, $max);
    }

    /**
     * 判断时候是否QQ号码
     *
     * @param $str
     * @return bool
     */
    public function isQQ($str, $name = 'QQ号', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_QQ);
    }

    /**
     * 判断经度
     *
     * @param $str
     * @param string $name
     * @param bool $nullable
     * @return bool
     */
    public function isLng($str, $name = '经度', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_LNG);
    }

    /**
     * 判断纬度
     *
     * @param $str
     * @return bool
     */
    public function isLat($str, $name = '纬度', $nullable = false)
    {
        return $this->regexp($str, $name, $nullable, self::REG_LAT);
    }

    /**
     * 判断日期
     * Y-m-d Y-m
     *
     * @param $str
     * @param string $date_format
     * @return bool
     */
    public function isDate($str, $date_format = 'Y-m-d')
    {
        if ( $date_format == 'Y-m' ) {
            list($year, $month) = explode('-', $str);
            return checkdate($month, '01', $year);
        }

        list($year, $month, $day) = explode('-', $str);

        return checkdate($month, $day, $year);
    }

    /**
     * 判断生日
     * Y-m-d Y-m
     *
     * @param $str
     * @param string $date_format
     * @param null $end_date
     * @return bool
     */
    public function isBirthday($str, $date_format = 'Y-m-d', $end_date = null)
    {
        $isDate = $this->isDate($str, $date_format);

        $current_date = $end_date ?: date($date_format);

        return $isDate ? ($str < $current_date ? true : false) : false;
    }

    /**
     * 验证字符串
     *
     * @param $str
     * @param $name
     * @param bool $nullable
     * @param int $max
     * @return bool
     */
    public function isString($str, $name, $nullable = false, $max = 255)
    {
        $string = new Strings();
        $str = $string->encodeContentWithEmoticon($str, false);
        return $this->regexp($str, $name, $nullable, '', 0, $max);
    }


    /**
     * 判断是否是闰年
     *
     * @param $year
     * @return bool
     */
    public function isLeapYear($year)
    {
        return ((($year % 4) == 0) && ((($year % 100) != 0) || (($year %400) == 0)));
    }

    /**
     * 判断身份证号码
     *
     * @param $idCard
     * @return bool
     */
    public function isIdCard($idCard)
    {
        // 只能是18位
        if(strlen($idCard) != 18){
            return false;
        }

        // 取出本体码
        $idCard_base = substr($idCard, 0, 17);

        // 取出校验码
        $verify_code = substr($idCard, 17, 1);

        // 加权因子
        $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);

        // 校验码对应值
        $verify_code_list = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');

        // 根据前17位计算校验码
        $total = 0;
        for($i=0; $i<17; $i++){
            $total += substr($idCard_base, $i, 1)*$factor[$i];
        }

        // 取模
        $mod = $total % 11;

        // 比较校验码
        if($verify_code == $verify_code_list[$mod]){
            return true;
        }

        return false;
    }

    /**
     * 判断整数
     *
     * @param $number
     * @param int $min
     * @param int $max
     * @return mixed
     */
    public function isInt($number, $min = 0, $max = 999999)
    {
        $int_options = array(
            "options" => array(
                "min_range" => $min,
                "max_range" => $max
            )
        );

        return filter_var($number, FILTER_VALIDATE_INT, $int_options) !== false;
    }

    /**
     * 判断小数
     *
     * @param $number
     * @param int $min
     * @param int $max
     */
    public function isFloat($number, $min = 0, $max = 999999)
    {

    }

    /**
     * 判断网址
     *
     * @param $url
     * @return bool
     */
    public function isUrl($url)
    {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }

    /**
     * 判断ip
     *
     * @param $ip
     * @return bool
     */
    public function isIp($ip)
    {
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }
}
